import numpy as np
import cv2
from decide import Decide

# 先test video测阈值，后调
BLACK_THRESHOLD = 120  # 黑棋阈值
WHITE_THRESHOLD = 160  # 白棋阈值

# 图像初步处理
def process_circles(img, lower_color, upper_color): # 处理圆形，返回中心坐标列表
    # 根据范围创建掩码
    mask = cv2.inRange(img, lower_color, upper_color)

    # 使用形态学操作（开运算）去除噪声
    kernel = np.ones((5, 5), np.uint8)
    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

    # 查找轮廓
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    centers = []
    for contour in contours:
        area = cv2.contourArea(contour)
        if area > 1000:
            perimeter = cv2.arcLength(contour, True)
            if perimeter > 0:
                circularity = 4 * np.pi * (area / (perimeter * perimeter))
                # 圆形度大于0.6
                if circularity > 0.6:
                    x, y, w, h = cv2.boundingRect(contour)
                    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
                    center_x = x + int(w / 2)
                    center_y = y + int(h / 2)
                    centers.append([center_x, center_y])
    centers.sort(key=lambda point: point[1])
    return centers[:5]

# 黑棋
def search_black_circle(img):
    lower_black = np.array([0, 0, 0], dtype=np.uint8)
    upper_black = np.array([BLACK_THRESHOLD, BLACK_THRESHOLD, BLACK_THRESHOLD], dtype=np.uint8)
    return process_circles(img, lower_black, upper_black)

# 白棋
def search_white_circle(img):
    lower_white = np.array([WHITE_THRESHOLD, WHITE_THRESHOLD, WHITE_THRESHOLD], dtype=np.uint8)
    upper_white = np.array([255, 255, 255], dtype=np.uint8)
    return process_circles(img, lower_white, upper_white)

# 映射棋盘
def map_to_tic_tac_toe(centers, img_width, img_height):
    grid_width = img_width // 3
    grid_height = img_height // 3
    board = [[0] * 3 for _ in range(3)]
    for center in centers:
        x, y = center
        col = min(2, x // grid_width)
        row = min(2, y // grid_height)
        board[row][col] = 1  # 调整为 row 表示行，col 表示列
    return board

# 保存棋盘状态
def save_board_to_txt(board, filename="棋盘状态.txt"):
    with open(filename, "w") as file:
        for row in board:
            file.write(" ".join(map(str, row)) + "\n")

# 对比棋子移动
def load_board_from_txt(filename="棋盘状态历史.txt"):
    try:
        with open(filename, "r") as file:
            board = [list(map(int, line.strip().split())) for line in file]
    except FileNotFoundError:
        print(f"未找到文件 {filename}")
        return None
    except Exception as e:
        print(f"加载棋盘文件时发生错误：{e}")
        return None
    return np.array(board, dtype=float)

# 计算旋转角度
def get_board_angle(img_cropped):
    gray = cv2.cvtColor(img_cropped, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    edges = cv2.Canny(blurred, 50, 150)
    contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    if not contours:
        return 0

    max_contour = max(contours, key=cv2.contourArea)
    rect = cv2.minAreaRect(max_contour)
    angle = rect[2]

    if angle < -45:
        angle += 90
    elif angle > 45:
        angle -= 90

    return angle

# 对比变化分析
def compare_boards(prev_board, curr_board):
    prev_flat = prev_board.flatten()
    curr_flat = curr_board.flatten()

    black_removed = []
    black_added = []
    white_removed = []
    white_added = []

    for i in range(3):
        for j in range(3):
            prev_val = prev_board[i][j]
            curr_val = curr_board[i][j]

            # 黑棋变化
            if prev_val == 1 and curr_val == 0:
                black_removed.append((i, j))
            elif prev_val == 0 and curr_val == 1:
                black_added.append((i, j))

            # 白棋变化
            if prev_val == -1 and curr_val == 0:
                white_removed.append((i, j))
            elif prev_val == 0 and curr_val == -1:
                white_added.append((i, j))

    # 找出可能的移动
    black_moves = []
    if len(black_removed) == 1 and len(black_added) == 1:
        black_moves = [(black_removed[0], black_added[0])]

    white_moves = []
    if len(white_removed) == 1 and len(white_added) == 1:
        white_moves = [(white_removed[0], white_added[0])]

    return {
        "black": black_moves,
        "white": white_moves
    }


def main():
    try:
        cap = cv2.VideoCapture(0) # 摄像头索引
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

        if not cap.isOpened():
            print("无法打开摄像头，尝试更换摄像头索引！")
            return

        print("等待棋盘稳定...")
        print("====================")
        print_history = []
        is_collecting = True
        current_angle = 0

        while True:
            ret, img_original = cap.read()
            if not ret:
                print("无法获取图像帧。退出程序...")
                break

            width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            if width != 640 or height != 480:
                img_original = cv2.resize(img_original, (640, 480))
                width, height = 640, 480

            # 裁剪取中心
            crop_size_w = 320
            crop_size_h = 320
            crop_x = (width - crop_size_w) // 2
            crop_y = (height - crop_size_h) // 2
            img_cropped = img_original[crop_y:crop_y + crop_size_h, crop_x:crop_x + crop_size_w]

            current_angle = get_board_angle(img_cropped)

            cv2.rectangle(img_original, (crop_x, crop_y), (crop_x + crop_size_w, crop_y + crop_size_h), (0, 0, 255), 2)

            if is_collecting:
                black_array = search_black_circle(img_cropped)
                white_array = search_white_circle(img_cropped)

                black_board = map_to_tic_tac_toe(black_array, img_cropped.shape[1], img_cropped.shape[0])
                white_board = map_to_tic_tac_toe(white_array, img_cropped.shape[1], img_cropped.shape[0])

                tic_tac_toe_board = [[0] * 3 for _ in range(3)]
                for i in range(3):
                    for j in range(3):
                        if black_board[i][j] == 1:
                            tic_tac_toe_board[i][j] = 1
                        if white_board[i][j] == 1:
                            tic_tac_toe_board[i][j] = -1

                print_history.append(tic_tac_toe_board)

                # 保持历史记录在10次以内
                if len(print_history) > 10:
                    print_history.pop(0)

                # 检查是否所有状态一致
                all_same = True
                if len(print_history) >= 10:
                    for state in print_history:
                        if state != print_history[0]:
                            all_same = False
                            break

                    if all_same:
                        current_board = print_history[0]
                        # 保存当前棋盘到文件
                        save_board_to_txt(current_board, "棋盘状态.txt")
                        print("棋盘状态稳定，初始状态已确定：")
                        for row in current_board:
                            print(row)
                        print("=" * 20)

                        # 加载历史棋盘和当前棋盘
                        prev_board = load_board_from_txt("棋盘状态历史.txt")
                        curr_board = load_board_from_txt("棋盘状态.txt")

                        # 对比棋盘变化
                        if prev_board is not None and curr_board is not None:
                            changes = compare_boards(prev_board, curr_board)
                            has_changes = False  # 检测标志位

                            if changes:
                                for color, moves in changes.items():
                                    for move in moves:  # 排除假性移动
                                        orig = move[0]
                                        new = move[1]
                                        print(
                                            f"({orig[0]}, {orig[1]}) -> ({new[0]}, {new[1]}),{current_angle:.2f},{color})")
                                        has_changes = True  # 标记
                            else:
                                has_changes = False

                            if not has_changes:
                                print(f"(A=B, {current_angle:.2f}， {color})")
                        else:
                            print("无历史棋盘或当前棋盘未加载成功...")

                        # 调用博弈逻辑
                        try:
                            dec = Decide()
                            ai_move = dec.play(np.array(current_board, dtype=float))
                            if ai_move is not None:
                                pass;
                        except Exception as e:
                            print("这棋对吗？")

                        # 保存当前棋盘为历史棋盘
                        save_board_to_txt(current_board, "棋盘状态历史.txt")

                        # 重置
                        current_board = None
                        print_history = []
                        is_collecting = False
                        print("按下 'n' 键重新开始采集图像，按下 'q' 键退出...")
                        print("====================")

            cv2.imshow("Original View", img_original)

            key = cv2.waitKey(1)
            if key == ord('n'):
                if is_collecting:
                    print("正在检测棋盘，无法响应 'n' 键...")
                else:
                    print("重新开始采集图像信息...")
                    print_history = []
                    is_collecting = True
            elif key == ord('q'):
                break

        cap.release()
        cv2.destroyAllWindows()

    except Exception as e:
        print(f"发生错误：{e}")


if __name__ == '__main__':
    main()